package com.tianyu.inspection.controller;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tianyu.inspection.common.Constants;
import com.tianyu.inspection.common.HttpRequest;
import com.tianyu.inspection.common.annotation.Permission;
import com.tianyu.inspection.common.component.AppConstants;
import com.tianyu.inspection.common.component.PdfModel;
import com.tianyu.inspection.common.component.Validate;
import com.tianyu.inspection.common.enums.RoState;
import com.tianyu.inspection.common.enums.Role;
import com.tianyu.inspection.common.model.JedisModel;
import com.tianyu.inspection.entity.FlyTask;
import com.tianyu.inspection.entity.model.OperateMo;
import com.tianyu.inspection.entity.model.QueryMo;
import com.tianyu.inspection.entity.vo.Ro;
import com.tianyu.inspection.entity.vo.ServiceRo;
import com.tianyu.inspection.service.api.IFlyTaskService;
import com.tianyu.inspection.service.telemetry.yukong.YkClient;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

import static com.tianyu.inspection.service.telemetry.yukong.YkClient.YK_PROJECT_ID_TOKEN_MAP;

/**********************************
 * @Author YSW
 * @Description 施工单位接口
 * @Date 2021/1/15 - 18:12
 **********************************/

@RestController
@RequestMapping("/api/2.0/flyTask")
@Slf4j
public class FlyTaskController {

    @Resource
    private IFlyTaskService flyTaskService;

    @Resource
    private AppConstants appConstants;

    @Resource
    private JedisModel jedisModel;

    @Resource
    private PdfModel pdfModel;

    @GetMapping(value = "/list")
    @Permission(value = 3, tags = Constants.API_COMPANY)
    public Ro<IPage<FlyTask>> getPageList(HttpServletRequest request, @RequestHeader("u-projectId") Integer projectId) {
        QueryMo queryMo = QueryMo.getQueryMo(request);
        request.removeAttribute("dangerCount");
        Ro<IPage<FlyTask>> ro = new Ro<>();
        queryMo.build(FlyTask.class, projectId);
        return ro.setContent(flyTaskService.searchListPage(queryMo));
    }

    @GetMapping(value = "/{id}")
    @Permission(value = 3, tags = Constants.API_COMPANY)
    public Ro<FlyTask> getOne(@PathVariable Integer id, @RequestHeader("u-projectId") Integer projectId) {
        Ro<FlyTask> ro = new Ro<>();
        if (Objects.isNull(id)) {
            return ro.setResultEnum(RoState.PARAMS_MISS_ERROR);
        }
        QueryMo queryMo = new QueryMo();
        queryMo.put("id", id);
        queryMo.build(FlyTask.class, projectId);
        FlyTask flyTask = flyTaskService.selectOne(queryMo);
        if (Objects.isNull(flyTask)) {
            ro.setMessage("未查询到数据");
        } else {
            ro.setContent(flyTask);
        }
        return ro;
    }

    /**
     * 飞行数据统计
     *
     * @return
     */
    @GetMapping(value = "/flight/statistics")
    @Permission(value = 3, tags = Constants.API_COMPANY)
    public Ro<Map<String, Object>> flightStatistics(@RequestHeader("u-projectId") Integer projectId,
                                                    HttpServletRequest request) {
        QueryMo queryMo = QueryMo.getQueryMo(request);
        Ro<Map<String, Object>> ro = new Ro<>(RoState.PARAMS_MISS_ERROR);
        if (request.getAttribute("roleId").equals(Role.ROLE_SUPER_ADMIN.getValue())) {
            if (Objects.isNull(queryMo.get("projectId"))) {
                return ro.setMessage("缺少参数[projectId]");
            }
        }
        queryMo.build(FlyTask.class, projectId);
        ModelMap map = flyTaskService.flightStatistics(queryMo);
        ro.setResultEnum(RoState.SUCCESS).setContent(map);
        return ro;
    }

    @PostMapping(value = "/admin/insert")
    @Permission(value = 1, tags = Constants.API_SUPER)
    public Ro<FlyTask> insert(@RequestBody OperateMo operateMo, @RequestHeader("u-projectId") Integer projectId) {
        Ro<FlyTask> ro = new Ro<>();
        operateMo.createBuild(FlyTask.class, projectId);
        if (operateMo.getEntity().size() == 0) {
            return ro.setResultEnum(RoState.FAIL).setMessage("无操作参数传入,请传参后重试");
        }
        if (!flyTaskService.insert(operateMo)) {
            ro.setResultEnum(RoState.FAIL);
        }
        return ro;
    }

    @Resource
    private Validate validateModel;

    @PatchMapping(value = "/modify")
    @Permission(value = 2, tags = Constants.API_ADMIN)
    public Ro<Object> modify(@RequestBody OperateMo operateMo, @RequestHeader("u-projectId") Integer projectId) {
        Ro<Object> ro = new Ro<>();
        final ServiceRo serviceRo = operateMo.updateBuild(FlyTask.class, projectId);
        if (!serviceRo.getResult()) {
            return ro.setResultEnum(RoState.FAIL).setContent(serviceRo.getData()).setMessage(serviceRo.getMessage());
        }
        if (operateMo.getEntity().size() == 0) {
            return ro.setResultEnum(RoState.FAIL).setMessage("无操作参数传入,请传参后重试");
        }
        if (Objects.isNull(operateMo.get("id"))) {
            return ro.setResultEnum(RoState.FAIL).setMessage("缺少[id]字段,请传参后重试");
        }
        if (!Constants.NUMBER_PATTERN.matcher(operateMo.get("id").toString()).matches()) {
            return ro.setResultEnum(RoState.FAIL).setMessage("[id]字段为数字,请重试");
        }
        String telemetryUrl = (String) operateMo.get("telemetryUrl");
        if (Objects.nonNull(telemetryUrl)) {
            if (validateModel.uploadTelemetryValidate(telemetryUrl)) {
                return ro.setResultEnum(RoState.FAIL).setMessage("参数错误[telemetryUrl],值不存在");
            }
        }
        operateMo.getEntity().remove("taskNumber");
        operateMo.getEntity().remove("taskSource");
        if (!flyTaskService.update(operateMo)) {
            return ro.setResultEnum(RoState.FAIL).setMessage("参数无匹配,修改失败");
        }
        return ro;
    }

    @PostMapping(value = "/platformTask")
    @Permission(value = 1, tags = Constants.API_SUPER)
    public Ro<FlyTask> cpTaskModifyByHand(@RequestBody OperateMo operateMo, @RequestHeader("u-projectId") Integer projectId) {
        Ro<FlyTask> ro = new Ro<>();
        Integer projectId0 = (Integer) operateMo.get("projectId");
        if (Objects.isNull(projectId0)) {
            return ro.setResultEnum(RoState.FAIL).setMessage("缺少参数[projectId]");
        } else {
            if (validateModel.projectIdValidate(projectId0)) {
                return ro.setResultEnum(RoState.FAIL).setMessage("参数错误[projectId],值不存在");
            }
        }
        operateMo.updateBuild(FlyTask.class, projectId);
        if (operateMo.getEntity().size() == 0) {
            return ro.setResultEnum(RoState.FAIL).setMessage("无操作参数传入,请传参后重试");
        }
        if (Objects.isNull(operateMo.get("id"))) {
            return ro.setResultEnum(RoState.FAIL).setMessage("缺少[id]字段,请传参后重试");
        }
        if (!Constants.NUMBER_PATTERN.matcher(operateMo.get("id").toString()).matches()) {
            return ro.setResultEnum(RoState.FAIL).setMessage("[id]字段为数字,请重试");
        }
        if (Objects.isNull(operateMo.get("taskNumber"))) {
            return ro.setResultEnum(RoState.FAIL).setMessage("缺少[taskNumber]字段,请传参后重试");
        }
        final int taskSource = Integer.parseInt(String.valueOf((operateMo.get("taskSource"))));
        if (taskSource == 2) {
            return doYkFlyTaskMsGet(operateMo, projectId, ro, projectId0);
        } else {
            return ro.setResultEnum(RoState.FAIL).setMessage("缺少参数[taskSource], 或该参数错误, 请修改后重试");
        }
    }

    private Ro<FlyTask> doYkFlyTaskMsGet(OperateMo operateMo, Integer projectId, Ro<FlyTask> ro, Integer projectId0) {
        final String token = YK_PROJECT_ID_TOKEN_MAP.get(projectId0);
        if (Objects.nonNull(token)) {
            final ModelMap taskInfo = HttpRequest.getTaskInfoFromYuKong(appConstants.yuKongHttpHost,
                    token, (String) operateMo.get("taskNumber"));
            final ModelMap taskVideo = HttpRequest.getTaskVideoFromYuKong(appConstants.yuKongHttpHost,
                    token, (String) operateMo.get("taskNumber"));
            if (Objects.nonNull(taskInfo) && taskInfo.get("state").equals(1)) {
                final Object startTime0 = taskInfo.get("startTime");
                final Object endTime0 = taskInfo.get("endTime");
                if (Objects.nonNull(startTime0)) {
                    long createTime = Long.parseLong(String.valueOf(startTime0));
                    operateMo.put("startTime", createTime);
                }
                if (Objects.nonNull(endTime0)) {
                    long endTime = Long.parseLong(String.valueOf(endTime0));
                    operateMo.put("endTime", endTime);
                }
                int flightDuration = Integer.parseInt(String.valueOf(taskInfo.get("flightDuration")));
                int flightMileage = Integer.parseInt(String.valueOf(taskInfo.get("flightMileage")));
                operateMo.put("flightDuration", flightDuration);
                operateMo.put("flightDistance", flightMileage);
                if (Objects.nonNull(taskVideo) && taskInfo.get("state").equals(1)) {
                    final JSONArray jsonArray = new ObjectMapper().convertValue(taskVideo.get("content"), JSONArray.class);
                    if (jsonArray.size() > 0) {
                        final JSONObject videoObject = jsonArray.getJSONObject(0);
                        if (videoObject.getInteger("mediaType") == 2) {
                            final String mediaUrl = videoObject.getString("mediaUrl");
                            operateMo.put("videoUrl", mediaUrl);
                            operateMo.put("startTime", new Date(videoObject.getLong("startTime")));
                            operateMo.put("endTime", new Date(videoObject.getLong("endTime")));
                        }
                    }
                }
                operateMo.updateBuild(FlyTask.class, projectId);
                operateMo.getEntity().remove("taskNumber");
                operateMo.getEntity().remove("taskSource");
                ro.setContent(new ObjectMapper().convertValue(operateMo.getEntity(), FlyTask.class));
                return ro.setResultEnum(RoState.SUCCESS);
            } else {
                return ro.setResultEnum(RoState.FAIL).setMessage("暂无任务[" + operateMo.get("taskNumber") + "]信息");
            }
        } else {
            return ro.setResultEnum(RoState.FAIL).setMessage("该项目未开启御空服务");
        }
    }

    @DeleteMapping(value = "/admin/delete/{id}")
    @Permission(value = 1, tags = Constants.API_SUPER)
    public Ro<FlyTask> delete(@PathVariable Integer id, @RequestHeader("u-projectId") Integer projectId) {
        Ro<FlyTask> ro = new Ro<>();
        QueryMo queryMo = new QueryMo();
        queryMo.put("id", id);
        queryMo.build(FlyTask.class, projectId);
        if (!flyTaskService.delete(queryMo)) {
            return ro.setResultEnum(RoState.FAIL).setMessage("无匹配ID,删除失败");
        }
        return ro;
    }

    @DeleteMapping(value = "/delete/logical/{id}")
    @Permission(value = 2, tags = Constants.API_ADMIN)
    public Ro<FlyTask> logicallyDelete(@PathVariable Integer id, @RequestHeader("u-projectId") Integer projectId) {
        Ro<FlyTask> ro = new Ro<>();
        QueryMo queryMo = new QueryMo();
        queryMo.put("id", id);
        queryMo.build(FlyTask.class, projectId);
        if (!flyTaskService.logicallyDelete(queryMo)) {
            ro.setResultEnum(RoState.FAIL).setMessage("无匹配ID,删除失败");
        }
        return ro;
    }


    @GetMapping(value = "/live-url")
    @Permission(value = 4, tags = Constants.API_PATROL)
    public Ro<Object> liveVideo(HttpServletRequest request, @RequestHeader("u-projectId") Integer projectId,
                                @RequestHeader("u-uid") Integer userId) {
        Ro<Object> ro = new Ro<>();
        QueryMo queryMo = QueryMo.getQueryMo(request);
        Object taskId = queryMo.get("ykTaskId");
        if (taskId == null) {
            return ro.setResultEnum(RoState.FAIL).setMessage("参数错误[ykTaskId]");
        }
        if (projectId == 1) {
            if (Objects.isNull(queryMo.get("projectId"))) {
                return ro.setResultEnum(RoState.FAIL).setMessage("超级管理员参数错误[projectId]");
            } else {
                projectId = Integer.valueOf(String.valueOf(queryMo.get("projectId")));
            }
        }
        //根据云平台云盒编号 获取直播 地址
        Channel channel = YkClient.YK_CHANNEL_MAP.get(projectId);
        if (Objects.isNull(channel)) {
            return ro.setResultEnum(RoState.FAIL).setMessage("御空未接入或已关闭");
        }
        ModelMap boxLiveVideoUrl = HttpRequest.getLiveTaskVideoFromYuKong(
                appConstants.yuKongHttpHost, YK_PROJECT_ID_TOKEN_MAP.get(projectId), String.valueOf(taskId));
        log.info(boxLiveVideoUrl + "");
        boxLiveVideoUrl.remove("state");
        if (boxLiveVideoUrl.size() < 1) {
            log.debug("项目[" + projectId + "] - 用户[" + userId + "] 获取御空任务[" + taskId + "]视频直播地址 -> 直播地址不存在");
            return ro.setResultEnum(RoState.FAIL).setMessage("御空任务[" + taskId + "]视频直播地址不存在");
        }
        log.debug("项目[" + projectId + "] - 用户[" + userId + "] 获取御空任务[" + taskId + "]视频直播地址 -> \n" + boxLiveVideoUrl);
        ro.setContent(boxLiveVideoUrl);
        return ro;
    }

    /**
     * 根据云平台任务编号 获取直播 地址
     *
     * @return
     */
    @GetMapping(value = "/liveVideo")
    @Permission(value = 4, tags = Constants.API_PATROL)
    public Ro<String> cpLiveVideo(HttpServletRequest request, @RequestHeader("u-projectId") Integer projectId,
                                  @RequestHeader("u-uid") Integer userId) {
        Ro<String> ro = new Ro<>();
        QueryMo queryMo = QueryMo.getQueryMo(request);
        Object type = queryMo.get("type");
        Object id = queryMo.get("id");
        String logInfo = null;
        if (type == null) {
            return ro.setResultEnum(RoState.FAIL).setMessage("参数错误[type]");
        }
        if (id == null) {
            return ro.setResultEnum(RoState.FAIL).setMessage("参数错误[id]");
        }
        if (projectId == 1) {
            if (Objects.isNull(queryMo.get("projectId"))) {
                return ro.setResultEnum(RoState.FAIL).setMessage("超级管理员参数错误[projectId]");
            } else {
                projectId = Integer.valueOf(String.valueOf(queryMo.get("projectId")));
            }
        }
        //根据云平台云盒编号 获取直播 地址
        if (Objects.equals(type, "2")) {
            Channel channel = YkClient.YK_CHANNEL_MAP.get(projectId);
            if (Objects.isNull(channel)) {
                return ro.setResultEnum(RoState.FAIL).setMessage("御空未接入或已关闭");
            }
            ModelMap boxLiveVideoUrl = HttpRequest.getLiveTaskVideoFromYuKong(
                    appConstants.yuKongHttpHost, YK_PROJECT_ID_TOKEN_MAP.get(projectId), String.valueOf(id));
            log.info(boxLiveVideoUrl + "");
            String videoUrl = (String) boxLiveVideoUrl.get("rtmp");
            if (Objects.isNull(videoUrl)) {
                log.debug("项目[" + projectId + "] - 用户[" + userId + "] 获取御空任务[" + id + "]视频直播地址 -> 直播地址不存在");
                return ro.setResultEnum(RoState.FAIL).setMessage("御空任务[" + id + "]视频直播地址不存在");
            }
            log.debug("项目[" + projectId + "] - 用户[" + userId + "] 获取御空任务[" + id + "]视频直播地址 -> \n" + videoUrl);
            ro.setContent(videoUrl);
        } else {
            ro.setResultEnum(RoState.FAIL).setContent("参数[type],类型不支持");
        }
        return ro;
    }

    /**
     * 飞行数据统计
     *
     * @return
     */
    @GetMapping(value = "/report/{id}")
    @Permission(value = 3, tags = Constants.API_COMPANY)
    public HttpServletResponse report(@PathVariable int id, HttpServletResponse response, @RequestHeader("u-projectId") Integer projectId) {
        try {
            ByteArrayOutputStream flayTaskReport = pdfModel.createFlayTaskReport(id, projectId);
            if (Objects.isNull(flayTaskReport)) {
                response.reset();
                response.setContentType("application/json;charset=UTF-8");
                Ro<Void> ro = new Ro<Void>(RoState.FAIL).setMessage("飞行任务不存在");
                byte[] responseBytes = JSON.toJSONString(ro).getBytes();
                OutputStream outputStream = new BufferedOutputStream(response.getOutputStream(), responseBytes.length);
                outputStream.write(responseBytes);
                outputStream.flush();
                outputStream.close();
                return response;
            }
            response.reset();
            response.addHeader("Content-Length", "" + flayTaskReport.size());
            response.addHeader("Access-Control-Allow-Origin", "*");
            response.setContentType("application/pdf;charset=UTF-8");
            response.setStatus(200);
            OutputStream outputStream = new BufferedOutputStream(response.getOutputStream(), flayTaskReport.size());
            outputStream.write(flayTaskReport.toByteArray());
            outputStream.flush();
            outputStream.close();
        } catch (Exception exception) {
            return response;
        }
        return response;
    }
}
